{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Lamini Classifier Example\n",
    "First let's install the Lamini Python SDK."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: lamini in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (3.2.3)\n",
      "Requirement already satisfied: tqdm in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (4.66.5)\n",
      "Requirement already satisfied: scikit-learn in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (1.5.2)\n",
      "Requirement already satisfied: requests in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (2.32.3)\n",
      "Requirement already satisfied: jsonlines in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (4.0.0)\n",
      "Requirement already satisfied: pandas in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (2.2.2)\n",
      "Requirement already satisfied: aiohttp in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (3.10.5)\n",
      "Requirement already satisfied: lamini-configuration[yaml] in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (0.8.3)\n",
      "Requirement already satisfied: numpy<2.0.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (1.26.4)\n",
      "Requirement already satisfied: azure-storage-blob in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini) (12.23.0)\n",
      "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (2.4.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (6.1.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (1.4.1)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (1.11.1)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (4.0.3)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (24.2.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from aiohttp->lamini) (1.3.1)\n",
      "Requirement already satisfied: cryptography>=2.1.4 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from azure-storage-blob->lamini) (43.0.1)\n",
      "Requirement already satisfied: typing-extensions>=4.6.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from azure-storage-blob->lamini) (4.12.2)\n",
      "Requirement already satisfied: isodate>=0.6.1 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from azure-storage-blob->lamini) (0.6.1)\n",
      "Requirement already satisfied: azure-core>=1.30.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from azure-storage-blob->lamini) (1.31.0)\n",
      "Requirement already satisfied: pyyaml<7.0,>=6.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from lamini-configuration[yaml]->lamini) (6.0.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from pandas->lamini) (2024.1)\n",
      "Requirement already satisfied: pytz>=2020.1 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from pandas->lamini) (2024.2)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from pandas->lamini) (2.9.0.post0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from requests->lamini) (3.10)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from requests->lamini) (3.3.2)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from requests->lamini) (1.26.20)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from requests->lamini) (2024.8.30)\n",
      "Requirement already satisfied: scipy>=1.6.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from scikit-learn->lamini) (1.14.1)\n",
      "Requirement already satisfied: threadpoolctl>=3.1.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from scikit-learn->lamini) (3.5.0)\n",
      "Requirement already satisfied: joblib>=1.2.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from scikit-learn->lamini) (1.4.2)\n",
      "Requirement already satisfied: six>=1.11.0 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from azure-core>=1.30.0->azure-storage-blob->lamini) (1.16.0)\n",
      "Requirement already satisfied: cffi>=1.12 in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from cryptography>=2.1.4->azure-storage-blob->lamini) (1.17.1)\n",
      "Requirement already satisfied: pycparser in /Users/bechols/.pyenv/versions/3.10.6/envs/lamini/lib/python3.10/site-packages (from cffi>=1.12->cryptography>=2.1.4->azure-storage-blob->lamini) (2.22)\n",
      "\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip available: \u001b[0m\u001b[31;49m22.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "pip install lamini --upgrade"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's import the Lamini Python SDK and set our API key. You can get your API key from app.lamini.ai - every user gets $300 in free credits to get started."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import lamini\n",
    "\n",
    "lamini.api_key = \"your-api-key-here\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we're all set up. The first thing we do is define a classifier - Lamini uses the concept of a \"project\" to contain one or many classifier versions for a given task.\n",
    "\n",
    "When you create a project, you define several key elements that can't be changed later:\n",
    "\n",
    "1. A project name\n",
    "2. A set of categories or classes that you need to categorize\n",
    "3. Descriptions of each category\n",
    "\n",
    "Projects also (eventually) contain one or many versions of:\n",
    "\n",
    "1. Example inputs and the expected output - we call this a dataset\n",
    "2. Models trained on the dataset(s) you've provided\n",
    "\n",
    "Below we're creating a project named \"ClassifierExample\" with a random suffix (just in case you're creating a few!).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from lamini.classify.lamini_classifier import LaminiClassifier\n",
    "import random\n",
    "\n",
    "cls = LaminiClassifier(\n",
    "    f\"ClassifierExample{random.randint(1000,9999)}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once the project is created, we define the classes. The more detailed the description, the higher your accuracy will be."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "classes = {\n",
    "    \"cat\": \"\"\"The cat (Felis catus), also referred to as domestic cat or house cat, is a small domesticated carnivorous mammal. It is the only domesticated species of the family Felidae. Advances in archaeology and genetics have shown that the domestication of the cat occurred in the Near East around 7500 BC. It is commonly kept as a pet and farm cat, but also ranges freely as a feral cat avoiding human contact. Valued by humans for companionship and its ability to kill vermin, the cat's retractable claws are adapted to killing small prey like mice and rats. It has a strong, flexible body, quick reflexes, and sharp teeth, and its night vision and sense of smell are well developed. It is a social species, but a solitary hunter and a crepuscular predator. Cat communication includes vocalizations—including meowing, purring, trilling, hissing, growling, and grunting–as well as body language. It can hear sounds too faint or too high in frequency for human ears, such as those made by small mammals. It secretes and perceives pheromones.\n",
    "            Domain:\tEukaryota\n",
    "            Kingdom:\tAnimalia\n",
    "            Phylum:\tChordata\n",
    "            Class:\tMammalia\n",
    "            Order:\tCarnivora\n",
    "            Suborder:\tFeliformia\n",
    "            Family:\tFelidae\n",
    "            Subfamily:\tFelinae\n",
    "            Genus:\tFelis\n",
    "            Species:\tF. catus[1]\"\"\",\n",
    "    \"dog\": \"\"\"The dog is a domesticated descendant of the wolf. Also called the domestic dog, it was selectively bred from an extinct population of wolves during the Late Pleistocene by hunter-gatherers. The dog was the first species to be domesticated by humans, over 14,000 years ago and before the development of agriculture. \n",
    "            Domain:\tEukaryota\n",
    "            Kingdom:\tAnimalia\n",
    "            Phylum:\tChordata\n",
    "            Class:\tMammalia\n",
    "            Order:\tCarnivora\n",
    "            Family:\tCanidae\n",
    "            Genus:\tCanis\"\"\",\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Adding example inputs is optional, but will also help with accuracy. You can always do this later - we'll show you how later in this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "examples = {\n",
    "    \"cat\": [\n",
    "        \"Tend to be independent and aloof.\",\n",
    "        \"Territorial and defensive .\",\n",
    "        \"Self-grooming animals, using their tongues to keep their coats clean and healthy.\",\n",
    "        \"Use body language and vocalizations, such as meowing and purring, to communicate.\"\n",
    "    ],\n",
    "    \"dog\": [\n",
    "        \"Social, pack-oriented, and tend to be more loyal to their human family.\",\n",
    "        \"Need regular grooming from their owners, including brushing and bathing.\",\n",
    "        \"Bark and growl to convey their messages.\",\n",
    "        \"Responsive to human commands and can be trained to perform a wide range of tasks.\"\n",
    "    ],\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we initialize the project. This can take about a minute per class, so we'll put in a simple timer to keep us updated on status."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Waiting for classifier to initialize\n",
      "Model ID: 8a9fe622-4555-4646-886a-dc94b16a56f2\n"
     ]
    }
   ],
   "source": [
    "resp = cls.initialize(classes, examples) \n",
    "\n",
    "import time\n",
    "\n",
    "while True:\n",
    "    print(\"Waiting for classifier to initialize\")\n",
    "    time.sleep(5)\n",
    "    resp = cls.train_status()\n",
    "    if resp[\"status\"] == \"completed\":\n",
    "        print(\"Model ID: \" + resp[\"model_id\"])\n",
    "        first_model_id = resp[\"model_id\"]\n",
    "        break\n",
    "    if resp[\"status\"] == \"failed\":\n",
    "        print(resp[\"status\"])\n",
    "        raise Exception(\"failed training\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cool, we have our first model version! Let's try it out with a quick test."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"classification\": [\n",
      "    [\n",
      "      {\n",
      "        \"class_id\": 1,\n",
      "        \"class_name\": \"dog\",\n",
      "        \"prob\": 0.5267619385770103\n",
      "      },\n",
      "      {\n",
      "        \"class_id\": 0,\n",
      "        \"class_name\": \"cat\",\n",
      "        \"prob\": 0.47323806142298974\n",
      "      }\n",
      "    ]\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "print(json.dumps(cls.classify(\"woof\"), indent=2))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can see how useful the classifier output is. We get a list of all the categories we defined in our project, plus a confidence score for each.\n",
    "\n",
    "We can go even further to easily quantify the accuracy of our classifier. Let's run an evaluation!\n",
    "\n",
    "What an evaluation means for a classifier: when you provide a set of inputs and the expected output, we can test the accuracy of the model on those inputs, and give you back both overall metrics as well as per-input assessment. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"eval_job_id\": \"1424247633\",\n",
      "  \"eval_data_id\": \"first_eval6032\",\n",
      "  \"metrics\": {\n",
      "    \"tuned_accuracy\": 1.0,\n",
      "    \"tuned_precision\": 1.0,\n",
      "    \"tuned_recall\": 1.0,\n",
      "    \"tuned_f1\": 1.0\n",
      "  },\n",
      "  \"status\": \"COMPLETED\",\n",
      "  \"predictions\": [\n",
      "    {\n",
      "      \"input\": \"woof\",\n",
      "      \"target\": \"dog\",\n",
      "      \"test_output\": \"dog\",\n",
      "      \"base_output\": null\n",
      "    },\n",
      "    {\n",
      "      \"input\": \"meow\",\n",
      "      \"target\": \"cat\",\n",
      "      \"test_output\": \"cat\",\n",
      "      \"base_output\": null\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "from lamini.one_evaler.one_evaler import LaminiOneEvaler\n",
    "\n",
    "eval = LaminiOneEvaler(\n",
    "    test_model_id=first_model_id,\n",
    "    eval_data_id=f\"first_eval{random.randint(1000,9999)}\",\n",
    "    eval_data=[{\"input\": \"woof\", \"target\": \"dog\"}, {\"input\": \"meow\", \"target\": \"cat\"}],\n",
    "    test_eval_type=\"classifier\",\n",
    ")\n",
    "\n",
    "print(json.dumps(eval.run(), indent=2))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That first run was ok, but we can do better. Let's add some more examples and retrain to improve accuracy. You control when to add data and when to train."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for classifier to train\n",
      "Waiting for classifier to train\n",
      "Model ID: 9739bf49-82ab-4e69-8149-5b891111516e\n"
     ]
    }
   ],
   "source": [
    "\n",
    "resp = cls.add(\n",
    "    \"additional_data\",\n",
    "    {\n",
    "        \"cat\": [\n",
    "            \"Cats spend up to sixteen hours a day sleeping, making them some of nature's most dedicated nappers.\",\n",
    "            \"Felines possess an extraordinary sense of balance thanks to their flexible backbone and righting reflex.\",\n",
    "            \"A cat's sandpaper-like tongue is covered in tiny hooks called papillae that help them groom themselves effectively.\",\n",
    "            \"Female cats tend to be right-pawed while male cats are more often left-pawed, according to scientific studies.\",\n",
    "            \"Ancient Egyptians showed their devotion to cats by mummifying them alongside their human companions.\",\n",
    "        ],\n",
    "        \"dog\": [\n",
    "            \"Dogs have evolved alongside humans for over 15,000 years, developing an uncanny ability to read our facial expressions and emotions.\",\n",
    "            \"The average dog can understand around 165 different words or signals, though some exceptional dogs can learn many more.\",\n",
    "            \"A dog's sense of smell is roughly 40 times greater than a human's, allowing them to detect diseases and track scents that are days old.\",\n",
    "            \"Unlike humans who have three cones in their eyes, dogs only have two, making them partially colorblind but excellent at detecting movement.\",\n",
    "            \"The Basenji breed is known as the 'barkless dog' because it produces an unusual yodel-like sound instead of a typical bark.\",\n",
    "        ],\n",
    "    },\n",
    ")\n",
    "\n",
    "resp = cls.train()\n",
    "\n",
    "while True:\n",
    "    print(\"Waiting for classifier to train\")\n",
    "    time.sleep(5)\n",
    "    resp = cls.train_status()\n",
    "    if resp[\"status\"] == \"completed\":\n",
    "        print(\"Model ID: \" + resp[\"model_id\"])\n",
    "        second_model_id = resp[\"model_id\"]\n",
    "        break\n",
    "    if resp[\"status\"] == \"failed\":\n",
    "        print(resp[\"status\"])\n",
    "        raise Exception(\"failed training\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great, now we have a second model version in our project! Let's run an eval and compare it to the first version."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running comparison eval between model versions 8a9fe622-4555-4646-886a-dc94b16a56f2 and 9739bf49-82ab-4e69-8149-5b891111516e\n",
      "{\n",
      "  \"eval_job_id\": \"2044167961\",\n",
      "  \"eval_data_id\": \"second_eval9291\",\n",
      "  \"metrics\": {\n",
      "    \"base_accuracy\": 1.0,\n",
      "    \"base_precision\": 1.0,\n",
      "    \"base_recall\": 1.0,\n",
      "    \"base_f1\": 1.0,\n",
      "    \"base_fuzzy_accuracy\": 1.0,\n",
      "    \"base_fuzzy_precision\": 1.0,\n",
      "    \"base_fuzzy_recall\": 1.0,\n",
      "    \"base_fuzzy_f1\": 1.0,\n",
      "    \"tuned_accuracy\": 1.0,\n",
      "    \"tuned_precision\": 1.0,\n",
      "    \"tuned_recall\": 1.0,\n",
      "    \"tuned_f1\": 1.0,\n",
      "    \"tuned_fuzzy_accuracy\": 1.0,\n",
      "    \"tuned_fuzzy_precision\": 1.0,\n",
      "    \"tuned_fuzzy_recall\": 1.0,\n",
      "    \"tuned_fuzzy_f1\": 1.0,\n",
      "    \"tuned_win_loss_ratio\": 0.0,\n",
      "    \"base_win_loss_ratio\": 0.0\n",
      "  },\n",
      "  \"status\": \"COMPLETED\",\n",
      "  \"predictions\": [\n",
      "    {\n",
      "      \"input\": \"woof\",\n",
      "      \"target\": \"dog\",\n",
      "      \"test_output\": \"dog\",\n",
      "      \"base_output\": \"dog\"\n",
      "    },\n",
      "    {\n",
      "      \"input\": \"meow\",\n",
      "      \"target\": \"cat\",\n",
      "      \"test_output\": \"cat\",\n",
      "      \"base_output\": \"cat\"\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "print(\"Running comparison eval between model versions \" + first_model_id + \" and \" + second_model_id)\n",
    "\n",
    "eval_2 = LaminiOneEvaler(\n",
    "    test_model_id=first_model_id,\n",
    "    eval_data_id=f\"second_eval{random.randint(1000,9999)}\",\n",
    "    eval_data=[{\"input\": \"woof\", \"target\": \"dog\"}, {\"input\": \"meow\", \"target\": \"cat\"}],\n",
    "    test_eval_type=\"classifier\",\n",
    "    base_model_id=second_model_id,\n",
    "    sbs=True,\n",
    "    fuzzy=True,\n",
    ")\n",
    "\n",
    "print(json.dumps(eval_2.run(), indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The eval output makes it easy to compare model versions overall, and to see exactly where the differences are, so you know exactly where to focus to improve your workflow.\n",
    "\n",
    "Happy classifying!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "lamini",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
